@@ -3,6 +3,9 @@ require 'assignable_types' |
||
| 3 | 3 |
require 'markdown_class_attributes' |
| 4 | 4 |
require 'utils' |
| 5 | 5 |
|
| 6 |
+# Agent is the core class in Huginn, representing a configurable, schedulable, reactive system with memory that can |
|
| 7 |
+# be sub-classed for many different purposes. Agents can emit Events, as well as receive them and react in many different ways. |
|
| 8 |
+# The basic Agent API is detailed on the Huginn wiki: https://github.com/cantino/huginn/wiki/Creating-a-new-agent |
|
| 6 | 9 |
class Agent < ActiveRecord::Base |
| 7 | 10 |
include AssignableTypes |
| 8 | 11 |
include MarkdownClassAttributes |
@@ -226,6 +229,9 @@ class Agent < ActiveRecord::Base |
||
| 226 | 229 |
!!@cannot_receive_events |
| 227 | 230 |
end |
| 228 | 231 |
|
| 232 |
+ # Find all Agents that have received Events since the last execution of this method. Update those Agents with |
|
| 233 |
+ # their new `last_checked_event_id` and queue each of the Agents to be called with #receive using `async_receive`. |
|
| 234 |
+ # This is called by bin/schedule.rb periodically. |
|
| 229 | 235 |
def receive! |
| 230 | 236 |
Agent.transaction do |
| 231 | 237 |
sql = Agent. |
@@ -256,9 +262,9 @@ class Agent < ActiveRecord::Base |
||
| 256 | 262 |
end |
| 257 | 263 |
|
| 258 | 264 |
# Given an Agent id and an array of Event ids, load the Agent, call #receive on it with the Event objects, and then |
| 259 |
- # save it with an updated _last_receive_at_ timestamp. |
|
| 265 |
+ # save it with an updated `last_receive_at` timestamp. |
|
| 260 | 266 |
# |
| 261 |
- # This method is tagged with _handle_asynchronously_ and will be delayed and run with delayed_job. It accepts Agent |
|
| 267 |
+ # This method is tagged with `handle_asynchronously` and will be delayed and run with delayed_job. It accepts Agent |
|
| 262 | 268 |
# and Event ids instead of a literal ActiveRecord models because it is preferable to serialize delayed_jobs with ids. |
| 263 | 269 |
def async_receive(agent_id, event_ids) |
| 264 | 270 |
agent = Agent.find(agent_id) |
@@ -273,6 +279,8 @@ class Agent < ActiveRecord::Base |
||
| 273 | 279 |
end |
| 274 | 280 |
handle_asynchronously :async_receive |
| 275 | 281 |
|
| 282 |
+ # Given a schedule name, run `check` via `bulk_check` on all Agents with that schedule. |
|
| 283 |
+ # This is called by bin/schedule.rb for each schedule in `SCHEDULES`. |
|
| 276 | 284 |
def run_schedule(schedule) |
| 277 | 285 |
types = where(:schedule => schedule).group(:type).pluck(:type) |
| 278 | 286 |
types.each do |type| |
@@ -280,7 +288,8 @@ class Agent < ActiveRecord::Base |
||
| 280 | 288 |
end |
| 281 | 289 |
end |
| 282 | 290 |
|
| 283 |
- # You can override this to define a custom bulk_check for your type of Agent. |
|
| 291 |
+ # Schedule `async_check`s for every Agent on the given schedule. This is normally called by `run_schedule` once |
|
| 292 |
+ # per type of agent, so you can override this to define custom bulk check behavior for your custom Agent type. |
|
| 284 | 293 |
def bulk_check(schedule) |
| 285 | 294 |
raise "Call #bulk_check on the appropriate subclass of Agent" if self == Agent |
| 286 | 295 |
where(:schedule => schedule).pluck("agents.id").each do |agent_id|
|
@@ -288,10 +297,11 @@ class Agent < ActiveRecord::Base |
||
| 288 | 297 |
end |
| 289 | 298 |
end |
| 290 | 299 |
|
| 291 |
- # Given an Agent id, load the Agent, call #check on it, and then save it with an updated _last_check_at_ timestamp. |
|
| 300 |
+ # Given an Agent id, load the Agent, call #check on it, and then save it with an updated `last_check_at` timestamp. |
|
| 292 | 301 |
# |
| 293 |
- # This method is tagged with _handle_asynchronously_ and will be delayed and run with delayed_job. It accepts an Agent |
|
| 294 |
- # id instead of a literal Agent because it is preferable to serialize delayed_jobs with ids. |
|
| 302 |
+ # This method is tagged with `handle_asynchronously` and will be delayed and run with delayed_job. It accepts an Agent |
|
| 303 |
+ # id instead of a literal Agent because it is preferable to serialize delayed_jobs with ids, instead of with the full |
|
| 304 |
+ # Agents. |
|
| 295 | 305 |
def async_check(agent_id) |
| 296 | 306 |
agent = Agent.find(agent_id) |
| 297 | 307 |
begin |
@@ -1,3 +1,6 @@ |
||
| 1 |
+# AgentLogs are temporary records of Agent activity, intended for debugging and error tracking. They can be viewed |
|
| 2 |
+# in Agents' detail pages. AgentLogs with a `level` of 4 or greater are considered "errors" and automatically update |
|
| 3 |
+# Agents' `last_error_log_at` column. These are often used to determine if an Agent is `working?`. |
|
| 1 | 4 |
class AgentLog < ActiveRecord::Base |
| 2 | 5 |
attr_accessible :agent, :inbound_event, :level, :message, :outbound_event |
| 3 | 6 |
|
@@ -1,3 +1,5 @@ |
||
| 1 |
+# Contacts are used only for the contact form on the Huginn website. If you host a public Huginn instance, you can use |
|
| 2 |
+# these to receive messages from visitors. |
|
| 1 | 3 |
class Contact < ActiveRecord::Base |
| 2 | 4 |
attr_accessible :email, :message, :name |
| 3 | 5 |
|
@@ -1,5 +1,8 @@ |
||
| 1 | 1 |
require 'json_serialized_field' |
| 2 | 2 |
|
| 3 |
+# Events are how Huginn Agents communicate and log information about the world. Events can be emitted and received by |
|
| 4 |
+# Agents. They contain a serialized `payload` of arbitrary JSON data, as well as optional `lat`, `lng`, and `expires_at` |
|
| 5 |
+# fields. |
|
| 3 | 6 |
class Event < ActiveRecord::Base |
| 4 | 7 |
include JSONSerializedField |
| 5 | 8 |
|
@@ -16,10 +19,13 @@ class Event < ActiveRecord::Base |
||
| 16 | 19 |
where("events.created_at > ?", timespan)
|
| 17 | 20 |
} |
| 18 | 21 |
|
| 22 |
+ # Emit this event again, as a new Event. |
|
| 19 | 23 |
def reemit! |
| 20 | 24 |
agent.create_event :payload => payload, :lat => lat, :lng => lng |
| 21 | 25 |
end |
| 22 | 26 |
|
| 27 |
+ # Look for Events whose `expires_at` is present and in the past. Remove those events and then update affected Agents' |
|
| 28 |
+ # `events_counts` cache columns. This method is called by bin/schedule.rb periodically. |
|
| 23 | 29 |
def self.cleanup_expired! |
| 24 | 30 |
affected_agents = Event.where("expires_at IS NOT NULL AND expires_at < ?", Time.now).group("agent_id").pluck(:agent_id)
|
| 25 | 31 |
Event.where("expires_at IS NOT NULL AND expires_at < ?", Time.now).delete_all
|
@@ -1,3 +1,4 @@ |
||
| 1 |
+# A Link connects Agents in a directed Event flow from the `source` to the `receiver`. |
|
| 1 | 2 |
class Link < ActiveRecord::Base |
| 2 | 3 |
attr_accessible :source_id, :receiver_id |
| 3 | 4 |
|
@@ -1,3 +1,4 @@ |
||
| 1 |
+# Huginn is designed to be a multi-User system. Users have many Agents (and Events created by those Agents). |
|
| 1 | 2 |
class User < ActiveRecord::Base |
| 2 | 3 |
# Include default devise modules. Others available are: |
| 3 | 4 |
# :token_authenticatable, :confirmable, |
@@ -1,5 +1,8 @@ |
||
| 1 | 1 |
#!/usr/bin/env ruby |
| 2 | 2 |
|
| 3 |
+# If you're using the backup gem, described on the Huginn wiki and at doc/deployment/backup, then you can use this |
|
| 4 |
+# utility to decrypt backups. |
|
| 5 |
+ |
|
| 3 | 6 |
in_file = ARGV.shift |
| 4 | 7 |
out_file = ARGV.shift || "decrypted_backup.tar" |
| 5 | 8 |
|
@@ -1,5 +1,8 @@ |
||
| 1 | 1 |
#!/usr/bin/env ruby |
| 2 | 2 |
|
| 3 |
+# This process is used to maintain Huginn's upkeep behavior, automatically running scheduled Agents and |
|
| 4 |
+# periodically propagating and expiring Events. It's typically run via foreman and the included Procfile. |
|
| 5 |
+ |
|
| 3 | 6 |
unless defined?(Rails) |
| 4 | 7 |
puts |
| 5 | 8 |
puts "Please run me with rails runner, for example:" |
@@ -1,5 +1,9 @@ |
||
| 1 | 1 |
#!/usr/bin/env ruby |
| 2 | 2 |
|
| 3 |
+# This process is used by TwitterStreamAgents to watch the Twitter stream in real time. It periodically checks for |
|
| 4 |
+# new or changed TwitterStreamAgents and starts to follow the stream for them. It is typically run by foreman via |
|
| 5 |
+# the included Procfile. |
|
| 6 |
+ |
|
| 3 | 7 |
unless defined?(Rails) |
| 4 | 8 |
puts |
| 5 | 9 |
puts "Please run me with rails runner, for example:" |